package com.java.comprehensive.thread.jihai.demo01;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author: 窦绍飞
 * @Date: 2022/6/26
 */
public class KillDemo {
	/**
	 * 启动10个线程
	 * 库存六个
	 * 生成一个合并队列
	 * 每个用户拿到自己的请求和响应
	 */
	public static void main(String[] args) throws InterruptedException {
		ExecutorService executorService = Executors.newCachedThreadPool();
		KillDemo killDemo = new KillDemo();
		killDemo.mergeJob();

		Thread.sleep(2000);
		List<Future<Result>> futures = new ArrayList<>();
		CountDownLatch count = new CountDownLatch(10);
		for (int i = 0; i < 10; i++) {
			final Long orderId = i + 100L;
			final Long userId = (long) i;
			Future<Result> submit = executorService.submit(() -> {
				count.countDown();
				count.await(1000, TimeUnit.SECONDS);
				return killDemo.operate(new UserRequest(orderId, userId, 1));
			});
			futures.add(submit);
		}
		futures.forEach(f -> {
			try {
				Result result = f.get(300, TimeUnit.MILLISECONDS);
				System.out.println(Thread.currentThread().getName() + "打印客户端请求响应" + result);
			} catch (InterruptedException | ExecutionException | TimeoutException e) {
				throw new RuntimeException(e);
			}
		});
	}

	private Integer stock = 6;
	private BlockingQueue<RequestPromise> blockingQueue = new LinkedBlockingQueue<>(1);

	/**
	 * 用户库存扣减
	 *
	 * @return
	 */
	public Result operate(UserRequest request) throws InterruptedException {

		//队列创建
		RequestPromise requestPromise = new RequestPromise(request);
		synchronized (requestPromise) {
			try {
				boolean offer = blockingQueue.offer(requestPromise, 100, TimeUnit.MILLISECONDS);
				if (!offer) {
					return new Result(false, "系统繁忙");
				}
				requestPromise.wait(200);
				if (requestPromise.getResult() == null) {
					return new Result(false, "等待超时");
				}
			} catch (InterruptedException e) {
				return new Result(false, "等待超时");
			}
		}
		return requestPromise.getResult();
	}

	private void mergeJob() {
		new Thread(() -> {
			List<RequestPromise> list = new ArrayList<>();
			while (true) {
				if (blockingQueue.isEmpty()) {
					try {
						Thread.sleep(10);
						continue;
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
				}
				int batchSize = blockingQueue.size();
				for (int i = 0; i < batchSize; i++) {
					list.add(blockingQueue.poll());
				}
				System.out.println(Thread.currentThread().getName() + ":合并扣减库存:" + list);
				//累计扣减库存
				int sum = list.stream().mapToInt(e -> e.getUserRequest().getCount()).sum();
				//两种情况 够扣 不够扣

				if (sum <= stock) {
					stock -= sum;
					list.forEach(l -> {
						synchronized (l) {
							l.notify();
						}
					});
					continue;
				}
				list.forEach(requestPromise -> {
					Integer count = requestPromise.getUserRequest().getCount();
					if (count <= sum) {
						stock -= count;
						requestPromise.setResult(new Result(true, "ok"));
					} else {
						requestPromise.setResult(new Result(false, "库存不足"));
					}
					synchronized (requestPromise) {
						requestPromise.notify();
					}
				});
				list.clear();

			}
		}, "mergeThread").start();
	}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class RequestPromise {
	private UserRequest userRequest;
	private Result result;

	public RequestPromise(UserRequest userRequest) {
		this.userRequest = userRequest;
	}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Result {
	private Boolean code;
	private String msg;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class UserRequest {
	private Long orderId;
	private Long userId;
	private Integer count;

	public UserRequest(Long orderId, Long userId) {
		this.orderId = orderId;
		this.userId = userId;
	}
}
